home *** CD-ROM | disk | FTP | other *** search
/ Celestin Apprentice 7 / Apprentice-Release7.iso / Source Code / C / Applications / Python 1.4 / Python 1.4 source / Modules / cgen.py < prev    next >
Encoding:
Python Source  |  1996-10-28  |  13.2 KB  |  540 lines  |  [TEXT/Pyth]

  1. ########################################################################
  2. # Copyright 1991-1995 by Stichting Mathematisch Centrum, Amsterdam,
  3. # The Netherlands.
  4. #
  5. #                         All Rights Reserved
  6. #
  7. # Permission to use, copy, modify, and distribute this software and its
  8. # documentation for any purpose and without fee is hereby granted,
  9. # provided that the above copyright notice appear in all copies and that
  10. # both that copyright notice and this permission notice appear in
  11. # supporting documentation, and that the names of Stichting Mathematisch
  12. # Centrum or CWI or Corporation for National Research Initiatives or
  13. # CNRI not be used in advertising or publicity pertaining to
  14. # distribution of the software without specific, written prior
  15. # permission.
  16. # While CWI is the initial source for this software, a modified version
  17. # is made available by the Corporation for National Research Initiatives
  18. # (CNRI) at the Internet address ftp://ftp.python.org.
  19. # STICHTING MATHEMATISCH CENTRUM AND CNRI DISCLAIM ALL WARRANTIES WITH
  20. # REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF
  21. # MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH
  22. # CENTRUM OR CNRI BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL
  23. # DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR
  24. # PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
  25. # TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  26. # PERFORMANCE OF THIS SOFTWARE.
  27. ########################################################################
  28.  
  29. # Python script to parse cstubs file for gl and generate C stubs.
  30. # usage: python cgen.py <cstubs >glmodule.c
  31. #
  32. # NOTE: You  must first make a python binary without the "GL" option
  33. #    before you can run this, when building Python for the first time.
  34. #    See comments in the Makefile.
  35. #
  36. # XXX BUG return arrays generate wrong code
  37. # XXX need to change error returns into gotos to free mallocked arrays
  38.  
  39.  
  40. import string
  41. import sys
  42.  
  43.  
  44. # Function to print to stderr
  45. #
  46. def err(*args):
  47.     savestdout = sys.stdout
  48.     try:
  49.         sys.stdout = sys.stderr
  50.         for i in args:
  51.             print i,
  52.         print
  53.     finally:
  54.         sys.stdout = savestdout
  55.  
  56.  
  57. # The set of digits that form a number
  58. #
  59. digits = '0123456789'
  60.  
  61.  
  62. # Function to extract a string of digits from the front of the string.
  63. # Returns the leading string of digits and the remaining string.
  64. # If no number is found, returns '' and the original string.
  65. #
  66. def getnum(s):
  67.     n = ''
  68.     while s and s[0] in digits:
  69.         n = n + s[0]
  70.         s = s[1:]
  71.     return n, s
  72.  
  73.  
  74. # Function to check if a string is a number
  75. #
  76. def isnum(s):
  77.     if not s: return 0
  78.     for c in s:
  79.         if not c in digits: return 0
  80.     return 1
  81.  
  82.  
  83. # Allowed function return types
  84. #
  85. return_types = ['void', 'short', 'long']
  86.  
  87.  
  88. # Allowed function argument types
  89. #
  90. arg_types = ['char', 'string', 'short', 'u_short', 'float', 'long', 'double']
  91.  
  92.  
  93. # Need to classify arguments as follows
  94. #    simple input variable
  95. #    simple output variable
  96. #    input array
  97. #    output array
  98. #    input giving size of some array
  99. #
  100. # Array dimensions can be specified as follows
  101. #    constant
  102. #    argN
  103. #    constant * argN
  104. #    retval
  105. #    constant * retval
  106. #
  107. # The dimensions given as constants * something are really
  108. # arrays of points where points are 2- 3- or 4-tuples
  109. #
  110. # We have to consider three lists:
  111. #    python input arguments
  112. #    C stub arguments (in & out)
  113. #    python output arguments (really return values)
  114. #
  115. # There is a mapping from python input arguments to the input arguments
  116. # of the C stub, and a further mapping from C stub arguments to the
  117. # python return values
  118.  
  119.  
  120. # Exception raised by checkarg() and generate()
  121. #
  122. arg_error = 'bad arg'
  123.  
  124.  
  125. # Function to check one argument.
  126. # Arguments: the type and the arg "name" (really mode plus subscript).
  127. # Raises arg_error if something's wrong.
  128. # Return type, mode, factor, rest of subscript; factor and rest may be empty.
  129. #
  130. def checkarg(type, arg):
  131.     #
  132.     # Turn "char *x" into "string x".
  133.     #
  134.     if type == 'char' and arg[0] == '*':
  135.         type = 'string'
  136.         arg = arg[1:]
  137.     #
  138.     # Check that the type is supported.
  139.     #
  140.     if type not in arg_types:
  141.         raise arg_error, ('bad type', type)
  142.     if type[:2] == 'u_':
  143.         type = 'unsigned ' + type[2:]
  144.     #
  145.     # Split it in the mode (first character) and the rest.
  146.     #
  147.     mode, rest = arg[:1], arg[1:]
  148.     #
  149.     # The mode must be 's' for send (= input) or 'r' for return argument.
  150.     #
  151.     if mode not in ('r', 's'):
  152.         raise arg_error, ('bad arg mode', mode)
  153.     #
  154.     # Is it a simple argument: if so, we are done.
  155.     #
  156.     if not rest:
  157.         return type, mode, '', ''
  158.     #    
  159.     # Not a simple argument; must be an array.
  160.     # The 'rest' must be a subscript enclosed in [ and ].
  161.     # The subscript must be one of the following forms,
  162.     # otherwise we don't handle it (where N is a number):
  163.     #    N
  164.     #    argN
  165.     #    retval
  166.     #    N*argN
  167.     #    N*retval
  168.     #
  169.     if rest[:1] <> '[' or rest[-1:] <> ']':
  170.         raise arg_error, ('subscript expected', rest)
  171.     sub = rest[1:-1]
  172.     #
  173.     # Is there a leading number?
  174.     #
  175.     num, sub = getnum(sub)
  176.     if num:
  177.         # There is a leading number
  178.         if not sub:
  179.             # The subscript is just a number
  180.             return type, mode, num, ''
  181.         if sub[:1] == '*':
  182.             # There is a factor prefix
  183.             sub = sub[1:]
  184.         else:
  185.             raise arg_error, ('\'*\' expected', sub)
  186.     if sub == 'retval':
  187.         # size is retval -- must be a reply argument
  188.         if mode <> 'r':
  189.             raise arg_error, ('non-r mode with [retval]', mode)
  190.     elif not isnum(sub) and (sub[:3] <> 'arg' or not isnum(sub[3:])):
  191.         raise arg_error, ('bad subscript', sub)
  192.     #
  193.     return type, mode, num, sub
  194.  
  195.  
  196. # List of functions for which we have generated stubs
  197. #
  198. functions = []
  199.  
  200.  
  201. # Generate the stub for the given function, using the database of argument
  202. # information build by successive calls to checkarg()
  203. #
  204. def generate(type, func, database):
  205.     #
  206.     # Check that we can handle this case:
  207.     # no variable size reply arrays yet
  208.     #
  209.     n_in_args = 0
  210.     n_out_args = 0
  211.     #
  212.     for a_type, a_mode, a_factor, a_sub in database:
  213.         if a_mode == 's':
  214.             n_in_args = n_in_args + 1
  215.         elif a_mode == 'r':
  216.             n_out_args = n_out_args + 1
  217.         else:
  218.             # Can't happen
  219.             raise arg_error, ('bad a_mode', a_mode)
  220.         if (a_mode == 'r' and a_sub) or a_sub == 'retval':
  221.             err('Function', func, 'too complicated:',
  222.                 a_type, a_mode, a_factor, a_sub)
  223.             print '/* XXX Too complicated to generate code for */'
  224.             return
  225.     #
  226.     functions.append(func)
  227.     #
  228.     # Stub header
  229.     #
  230.     print
  231.     print 'static object *'
  232.     print 'gl_' + func + '(self, args)'
  233.     print '\tobject *self;'
  234.     print '\tobject *args;'
  235.     print '{'
  236.     #
  237.     # Declare return value if any
  238.     #
  239.     if type <> 'void':
  240.         print '\t' + type, 'retval;'
  241.     #
  242.     # Declare arguments
  243.     #
  244.     for i in range(len(database)):
  245.         a_type, a_mode, a_factor, a_sub = database[i]
  246.         print '\t' + a_type,
  247.         brac = ket = ''
  248.         if a_sub and not isnum(a_sub):
  249.             if a_factor:
  250.                 brac = '('
  251.                 ket = ')'
  252.             print brac + '*',
  253.         print 'arg' + `i+1` + ket,
  254.         if a_sub and isnum(a_sub):
  255.             print '[', a_sub, ']',
  256.         if a_factor:
  257.             print '[', a_factor, ']',
  258.         print ';'
  259.     #
  260.     # Find input arguments derived from array sizes
  261.     #
  262.     for i in range(len(database)):
  263.         a_type, a_mode, a_factor, a_sub = database[i]
  264.         if a_mode == 's' and a_sub[:3] == 'arg' and isnum(a_sub[3:]):
  265.             # Sending a variable-length array
  266.             n = eval(a_sub[3:])
  267.             if 1 <= n <= len(database):
  268.                 b_type, b_mode, b_factor, b_sub = database[n-1]
  269.                 if b_mode == 's':
  270.                     database[n-1] = b_type, 'i', a_factor, `i`
  271.                     n_in_args = n_in_args - 1
  272.     #
  273.     # Assign argument positions in the Python argument list
  274.     #
  275.     in_pos = []
  276.     i_in = 0
  277.     for i in range(len(database)):
  278.         a_type, a_mode, a_factor, a_sub = database[i]
  279.         if a_mode == 's':
  280.             in_pos.append(i_in)
  281.             i_in = i_in + 1
  282.         else:
  283.             in_pos.append(-1)
  284.     #
  285.     # Get input arguments
  286.     #
  287.     for i in range(len(database)):
  288.         a_type, a_mode, a_factor, a_sub = database[i]
  289.         if a_type[:9] == 'unsigned ':
  290.             xtype = a_type[9:]
  291.         else:
  292.             xtype = a_type
  293.         if a_mode == 'i':
  294.             #
  295.             # Implicit argument;
  296.             # a_factor is divisor if present,
  297.             # a_sub indicates which arg (`database index`)
  298.             #
  299.             j = eval(a_sub)
  300.             print '\tif',
  301.             print '(!geti' + xtype + 'arraysize(args,',
  302.             print `n_in_args` + ',',
  303.             print `in_pos[j]` + ',',
  304.             if xtype <> a_type:
  305.                 print '('+xtype+' *)',
  306.             print '&arg' + `i+1` + '))'
  307.             print '\t\treturn NULL;'
  308.             if a_factor:
  309.                 print '\targ' + `i+1`,
  310.                 print '= arg' + `i+1`,
  311.                 print '/', a_factor + ';'
  312.         elif a_mode == 's':
  313.             if a_sub and not isnum(a_sub):
  314.                 # Allocate memory for varsize array
  315.                 print '\tif ((arg' + `i+1`, '=',
  316.                 if a_factor:
  317.                     print '('+a_type+'(*)['+a_factor+'])',
  318.                 print 'NEW(' + a_type, ',',
  319.                 if a_factor:
  320.                     print a_factor, '*',
  321.                 print a_sub, ')) == NULL)'
  322.                 print '\t\treturn err_nomem();'
  323.             print '\tif',
  324.             if a_factor or a_sub: # Get a fixed-size array array
  325.                 print '(!geti' + xtype + 'array(args,',
  326.                 print `n_in_args` + ',',
  327.                 print `in_pos[i]` + ',',
  328.                 if a_factor: print a_factor,
  329.                 if a_factor and a_sub: print '*',
  330.                 if a_sub: print a_sub,
  331.                 print ',',
  332.                 if (a_sub and a_factor) or xtype <> a_type:
  333.                     print '('+xtype+' *)',
  334.                 print 'arg' + `i+1` + '))'
  335.             else: # Get a simple variable
  336.                 print '(!geti' + xtype + 'arg(args,',
  337.                 print `n_in_args` + ',',
  338.                 print `in_pos[i]` + ',',
  339.                 if xtype <> a_type:
  340.                     print '('+xtype+' *)',
  341.                 print '&arg' + `i+1` + '))'
  342.             print '\t\treturn NULL;'
  343.     #
  344.     # Begin of function call
  345.     #
  346.     if type <> 'void':
  347.         print '\tretval =', func + '(',
  348.     else:
  349.         print '\t' + func + '(',
  350.     #
  351.     # Argument list
  352.     #
  353.     for i in range(len(database)):
  354.         if i > 0: print ',',
  355.         a_type, a_mode, a_factor, a_sub = database[i]
  356.         if a_mode == 'r' and not a_factor:
  357.             print '&',
  358.         print 'arg' + `i+1`,
  359.     #
  360.     # End of function call
  361.     #
  362.     print ');'
  363.     #
  364.     # Free varsize arrays
  365.     #
  366.     for i in range(len(database)):
  367.         a_type, a_mode, a_factor, a_sub = database[i]
  368.         if a_mode == 's' and a_sub and not isnum(a_sub):
  369.             print '\tDEL(arg' + `i+1` + ');'
  370.     #
  371.     # Return
  372.     #
  373.     if n_out_args:
  374.         #
  375.         # Multiple return values -- construct a tuple
  376.         #
  377.         if type <> 'void':
  378.             n_out_args = n_out_args + 1
  379.         if n_out_args == 1:
  380.             for i in range(len(database)):
  381.                 a_type, a_mode, a_factor, a_sub = database[i]
  382.                 if a_mode == 'r':
  383.                     break
  384.             else:
  385.                 raise arg_error, 'expected r arg not found'
  386.             print '\treturn',
  387.             print mkobject(a_type, 'arg' + `i+1`) + ';'
  388.         else:
  389.             print '\t{ object *v = newtupleobject(',
  390.             print n_out_args, ');'
  391.             print '\t  if (v == NULL) return NULL;'
  392.             i_out = 0
  393.             if type <> 'void':
  394.                 print '\t  settupleitem(v,',
  395.                 print `i_out` + ',',
  396.                 print mkobject(type, 'retval') + ');'
  397.                 i_out = i_out + 1
  398.             for i in range(len(database)):
  399.                 a_type, a_mode, a_factor, a_sub = database[i]
  400.                 if a_mode == 'r':
  401.                     print '\t  settupleitem(v,',
  402.                     print `i_out` + ',',
  403.                     s = mkobject(a_type, 'arg' + `i+1`)
  404.                     print s + ');'
  405.                     i_out = i_out + 1
  406.             print '\t  return v;'
  407.             print '\t}'
  408.     else:
  409.         #
  410.         # Simple function return
  411.         # Return None or return value
  412.         #
  413.         if type == 'void':
  414.             print '\tINCREF(None);'
  415.             print '\treturn None;'
  416.         else:
  417.             print '\treturn', mkobject(type, 'retval') + ';'
  418.     #
  419.     # Stub body closing brace
  420.     #
  421.     print '}'
  422.  
  423.  
  424. # Subroutine to return a function call to mknew<type>object(<arg>)
  425. #
  426. def mkobject(type, arg):
  427.     if type[:9] == 'unsigned ':
  428.         type = type[9:]
  429.         return 'mknew' + type + 'object((' + type + ') ' + arg + ')'
  430.     return 'mknew' + type + 'object(' + arg + ')'
  431.  
  432.  
  433. defined_archs = []
  434.  
  435. # usage: cgen [ -Dmach ... ] [ file ]
  436. for arg in sys.argv[1:]:
  437.     if arg[:2] == '-D':
  438.         defined_archs.append(arg[2:])
  439.     else:
  440.         # Open optional file argument
  441.         sys.stdin = open(arg, 'r')
  442.  
  443.  
  444. # Input line number
  445. lno = 0
  446.  
  447.  
  448. # Input is divided in two parts, separated by a line containing '%%'.
  449. #    <part1>        -- literally copied to stdout
  450. #    <part2>        -- stub definitions
  451.  
  452. # Variable indicating the current input part.
  453. #
  454. part = 1
  455.  
  456. # Main loop over the input
  457. #
  458. while 1:
  459.     try:
  460.         line = raw_input()
  461.     except EOFError:
  462.         break
  463.     #
  464.     lno = lno+1
  465.     words = string.split(line)
  466.     #
  467.     if part == 1:
  468.         #
  469.         # In part 1, copy everything literally
  470.         # except look for a line of just '%%'
  471.         #
  472.         if words == ['%%']:
  473.             part = part + 1
  474.         else:
  475.             #
  476.             # Look for names of manually written
  477.             # stubs: a single percent followed by the name
  478.             # of the function in Python.
  479.             # The stub name is derived by prefixing 'gl_'.
  480.             #
  481.             if words and words[0][0] == '%':
  482.                 func = words[0][1:]
  483.                 if (not func) and words[1:]:
  484.                     func = words[1]
  485.                 if func:
  486.                     functions.append(func)
  487.             else:
  488.                 print line
  489.         continue
  490.     if not words:
  491.         continue        # skip empty line
  492.     elif words[0] == 'if':
  493.         # if XXX rest
  494.         # if !XXX rest
  495.         if words[1][0] == '!':
  496.             if words[1][1:] in defined_archs:
  497.                 continue
  498.         elif words[1] not in defined_archs:
  499.             continue
  500.         words = words[2:]
  501.     if words[0] == '#include':
  502.         print line
  503.     elif words[0][:1] == '#':
  504.         pass            # ignore comment
  505.     elif words[0] not in return_types:
  506.         err('Line', lno, ': bad return type :', words[0])
  507.     elif len(words) < 2:
  508.         err('Line', lno, ': no funcname :', line)
  509.     else:
  510.         if len(words) % 2 <> 0:
  511.             err('Line', lno, ': odd argument list :', words[2:])
  512.         else:
  513.             database = []
  514.             try:
  515.                 for i in range(2, len(words), 2):
  516.                     x = checkarg(words[i], words[i+1])
  517.                     database.append(x)
  518.                 print
  519.                 print '/*',
  520.                 for w in words: print w,
  521.                 print '*/'
  522.                 generate(words[0], words[1], database)
  523.             except arg_error, msg:
  524.                 err('Line', lno, ':', msg)
  525.  
  526.  
  527. print
  528. print 'static struct methodlist gl_methods[] = {'
  529. for func in functions:
  530.     print '\t{"' + func + '", gl_' + func + '},'
  531. print '\t{NULL, NULL} /* Sentinel */'
  532. print '};'
  533. print
  534. print 'initgl()'
  535. print '{'
  536. print '\tinitmodule("gl", gl_methods);'
  537. print '}'
  538.